﻿using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

namespace net.xBei.Security {
    /// <summary>
    /// 加密解密
    /// </summary>
    public sealed class EncryptUtils {
        #region Base64 编码解码
        /// <summary>
        /// Base64加密
        /// </summary>
        /// <param name="input">需要加密的字符串</param>
        /// <returns></returns>
        public static string Base64Encrypt(string input) => Base64Encrypt(input, Encoding.UTF8);

        /// <summary>
        /// Base64加密
        /// </summary>
        /// <param name="input">需要加密的字符串</param>
        /// <param name="encode">字符编码</param>
        /// <returns></returns>
        public static string Base64Encrypt(string input, Encoding encode) => Convert.ToBase64String(encode.GetBytes(input));
        /// <summary>
        /// Base64加密
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static string Base64Encrypt(byte[] input) => Convert.ToBase64String(input);

        /// <summary>
        /// Base64解密
        /// </summary>
        /// <param name="input">需要解密的字符串</param>
        /// <returns></returns>
        public static string Base64Decrypt(string input) {
            return Base64Decrypt(input, Encoding.UTF8);
        }
        /// <summary>
        /// Base64解密
        /// </summary>
        /// <param name="input">需要解密的字符串</param>
        /// <returns></returns>
        public static byte[] Base64DecryptBuffer(string input) {
            return Convert.FromBase64String(input);
        }
        /// <summary>
        /// Base64字符串转16进制字符串
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static string Base64ToHex(string input) {
            var t = Convert.FromBase64String(input);
            var sb = new StringBuilder(32);
            for (var i = 0; i < t.Length; i++) {
                sb.Append(t[i].ToString("x2"));
            }

            return sb.ToString();
        }

        /// <summary>
        /// Base64解密
        /// </summary>
        /// <param name="input">需要解密的字符串</param>
        /// <param name="encode">字符的编码</param>
        /// <returns></returns>
        public static string Base64Decrypt(string input, Encoding encode) {
            return encode.GetString(Convert.FromBase64String(input));
        }
        #endregion

        #region DES加密解密
        /// <summary>
        /// DES加密
        /// </summary>
        /// <param name="data">加密数据</param>
        /// <param name="key">8位字符的密钥字符串</param>
        /// <param name="iv">8位字符的初始化向量字符串</param>
        /// <returns></returns>
        public static string DesEncrypt(string data, string key, string iv) {
            var byKey = Encoding.ASCII.GetBytes(key);
            var byIv = Encoding.ASCII.GetBytes(iv);

            using var cryptoProvider = DES.Create();
            using var ms = new MemoryStream();
            var cst = new CryptoStream(ms, cryptoProvider.CreateEncryptor(byKey, byIv), CryptoStreamMode.Write);
            using (var sw = new StreamWriter(cst)) {
                sw.Write(data);
                sw.Flush();
                cst.FlushFinalBlock();
                sw.Flush();
            }
            return Convert.ToBase64String(ms.GetBuffer(), 0, (int)ms.Length);
        }

        /// <summary>
        /// DES解密
        /// </summary>
        /// <param name="data">解密数据</param>
        /// <param name="key">8位字符的密钥字符串(需要和加密时相同)</param>
        /// <param name="iv">8位字符的初始化向量字符串(需要和加密时相同)</param>
        /// <returns></returns>
        public static string DesDecrypt(string data, string key, string iv) {
            var byKey = Encoding.ASCII.GetBytes(key);
            var byIv = Encoding.ASCII.GetBytes(iv);

            byte[] byEnc;
            try {
                byEnc = Convert.FromBase64String(data);
            } catch {
                return string.Empty;
            }

            using var cryptoProvider = DES.Create();
            var ms = new MemoryStream(byEnc);
            var cst = new CryptoStream(ms, cryptoProvider.CreateDecryptor(byKey, byIv), CryptoStreamMode.Read);
            using var sr = new StreamReader(cst);
            return sr.ReadToEnd();
        }
        #endregion

        #region 3DES 加密解密
        /// <summary>
        /// 3DES 加密
        /// </summary>
        /// <param name="data"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public static string Des3Encrypt(string data, string key) {
            using var des = TripleDES.Create();
            des.Key = Encoding.ASCII.GetBytes(key);
            des.Mode = CipherMode.CBC;
            des.Padding = PaddingMode.PKCS7;

            var desEncrypt = des.CreateEncryptor();
            var buffer = Encoding.ASCII.GetBytes(data);
            return Convert.ToBase64String(desEncrypt.TransformFinalBlock(buffer, 0, buffer.Length));
        }
        /// <summary>
        /// 3DES 解密
        /// </summary>
        /// <param name="data"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public static string Des3Decrypt(string data, string key) {
            using var des = TripleDES.Create();
            des.Key = Encoding.ASCII.GetBytes(key);
            des.Mode = CipherMode.CBC;
            des.Padding = PaddingMode.PKCS7;
            var desDecrypt = des.CreateDecryptor();
            var result = "";
            try {
                var buffer = Convert.FromBase64String(data);
                result = Encoding.ASCII.GetString(desDecrypt.TransformFinalBlock(buffer, 0, buffer.Length));
            } catch (Exception) {
                // ignored
            }
            return result;
        }
        #endregion
    }
}
